`
https://leetcode.cn/problems/contains-duplicate-iii/
`

/**
 * @param {number[]} nums
 * @param {number} indexDiff
 * @param {number} valueDiff
 * @return {boolean}
 */
var containsNearbyAlmostDuplicate = function (nums, indexDiff, valueDiff) {
  // 分桶策略和滑动窗口
  let left = 0, right = 0

  // 一个键值对表示一个桶
  const window = new Map()

  // 桶大小
  const bucketSize = valueDiff + 1

  // 维护一个长度为 indexDiff 的滑动窗口
  while (right < nums.length) {
    // 获取新加入滑动窗口的元素
    const num = nums[right]
    // 计算该元素处于哪个桶
    const bucket = Math.floor(num / bucketSize)
    right++

    // 滑动窗口内存在相同桶的元素，同一桶内的元素差值必然小于等于 valueDiff
    // 说明找到满足abs(nums[i] - nums[j]) <= t的元素对，返回 true
    if (window.has(bucket)) {
      return true
    }

    // 检查相邻桶（bucket ± 1），若相邻桶中的元素与当前元素差不超过t，则满足条件，返回 true
    if (window.has(bucket - 1) && Math.abs(num - window.get(bucket - 1)) <= valueDiff) {
      return true
    }
    if (window.has(bucket + 1) && Math.abs(num - window.get(bucket + 1)) <= valueDiff) {
      return true
    }

    // 将当前元素加入对应的桶
    window.set(bucket, num)

    // 滑动窗口长度大于 indexDiff ，缩小窗口
    if (right - left > indexDiff) {
      window.delete(Math.floor(nums[left] / bucketSize))
      left++
    }
  }

  return false
};